package drds.plus.sql_process.abstract_syntax_tree.node.query;

import drds.plus.common.jdbc.Parameters;
import drds.plus.sql_process.abstract_syntax_tree.ObjectCreateFactory;
import drds.plus.sql_process.abstract_syntax_tree.execute_plan.ExecutePlan;
import drds.plus.sql_process.abstract_syntax_tree.execute_plan.query.LockMode;
import drds.plus.sql_process.abstract_syntax_tree.execute_plan.query.QueryConcurrencyWay;
import drds.plus.sql_process.abstract_syntax_tree.expression.bind_value.BindValue;
import drds.plus.sql_process.abstract_syntax_tree.expression.item.Item;
import drds.plus.sql_process.abstract_syntax_tree.expression.item.function.BooleanFilter;
import drds.plus.sql_process.abstract_syntax_tree.expression.item.function.Filter;
import drds.plus.sql_process.abstract_syntax_tree.expression.item.function.Function;
import drds.plus.sql_process.abstract_syntax_tree.expression.order_by.OrderBy;
import drds.plus.sql_process.abstract_syntax_tree.node.Node;
import drds.plus.sql_process.abstract_syntax_tree.node.query.build.QueryBuilder;
import drds.plus.sql_process.optimizer.pre_processor.SubQueryPreProcessor;
import drds.plus.sql_process.type.Type;
import drds.plus.sql_process.utils.DnfFilters;
import drds.plus.sql_process.utils.Filters;
import drds.plus.sql_process.utils.OptimizerUtils;
import drds.tools.$;
import lombok.Getter;
import lombok.Setter;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;


public abstract class Query extends Node<Query> {
    @Setter
    @Getter
    protected boolean consistent = true;
    @Setter
    @Getter
    protected LockMode lockMode = LockMode.undefined;
    @Setter
    @Getter
    protected QueryConcurrencyWay queryConcurrencyWay;
    @Setter
    @Getter
    protected boolean needBuild = true;

    /**
     * 上一层父节点，比如子查询会依赖父节点的字段信息
     */
    @Setter
    @Getter
    protected Query parent = null;

    /**
     * 当前QueryNode的别名
     */
    @Setter
    @Getter
    protected String alias;
    /**
     * <pre>
     *  ============================================================
     *  标准模式
     *  ============================================================
     * </pre>
     */
    /**
     * select查询中的列
     */
    @Setter
    @Getter
    protected List<Item> selectItemList = new ArrayList<Item>();

    /**
     * 依赖的所有列，可以理解为selectItemList + implicit selectItemList的总合
     */
    @Setter
    @Getter
    protected List<Item> referedItemList = new ArrayList<Item>();
    /**
     * 包含所有子节点的filter，用于拼sql
     */
    @Setter
    @Getter
    protected Filter allWhereFilter = null;

    @Setter
    @Getter
    protected Filter where = null;
    @Setter
    @Getter
    protected Filter indexQueryKeyFilter;
    @Setter
    @Getter
    protected Filter resultFilter;
    @Setter
    @Getter
    /**
     * 显式的由查询接口指定的group by，注意需要保证顺序
     */
    protected List<OrderBy> groupByList = new LinkedList<OrderBy>();
    @Setter
    @Getter
    /**
     * having条件
     */
    protected Filter having;
    @Setter
    @Getter
    /**
     * 显式的由查询接口指定的orderBy，注意需要保证顺序
     */
    protected List<OrderBy> orderByList = new LinkedList<OrderBy>();
    @Setter
    @Getter
    /**
     * 从哪里开始
     */
    protected Comparable limitFrom = null;
    @Setter
    @Getter
    /**
     * 到哪里结束
     */
    protected Comparable limitTo = null;
    /**
     * 是否为存在聚合信息，比如出现limit/group by/count/max等，此节点就会被标记为true，不允许进行join sort join的展开优化
     */
    @Setter
    @Getter
    protected boolean existAggregateExpression = false;

    /**
     * <pre>
     *  ============================================================
     *  子查询
     *  ============================================================
     * </pre>
     */
    /**
     * 当前节点是否为子查询
     */
    @Setter
    @Getter
    protected boolean subQuery = false;
    /**
     * 针对where id = (subQuery), 给subQuery设定一个唯一id，展开为merge后，可以避免执行器cache subquery结果，避免重复执行
     */
    @Setter
    @Getter
    protected Long subQueryId = 0l;
    /**
     * 专门针对子查询的filter
     */
    @Setter
    @Getter
    protected Filter subQueryFunctionFilter;
    /**
     * 如果出现subQuery，内外都存在别名时，内部的别名为subAlias，外部使用的别名为alias
     */
    @Setter
    @Getter
    protected String subAlias;


    /**
     * 标记一下是否为correlated subQuery，此子查询不可提前计算，需要依赖外查询的当前计算值进行计算，比如exist查询
     */
    @Setter
    @Getter
    protected boolean correlatedSubQuery = false;
    /**
     * 在correlatedSubQuery为true的情况下，记录对应的Correlated columnNameList
     */
    @Setter
    @Getter
    protected List<Item> correlatedSubQueryItemList = new ArrayList<Item>();


    /**
     * <pre>
     *  ============================================================
     *  join
     *  ============================================================
     * </pre>
     */
    /**
     * join的子节点
     */
    @Setter
    @Getter
    protected List<Node> nodeList = new ArrayList<Node>(2);
    /**
     * 非column=column的join列
     */
    @Setter
    @Getter
    protected Filter otherJoinOnFilter;


    public Query() {
        super();
    }

    /**
     * 获取完整的order by列信息(包括隐藏，比如group by会转化为order by)
     */
    public abstract List<OrderBy> getCompleteOrderByList();

    /**
     * 获取builder对象
     */
    public abstract QueryBuilder getQueryNodeBuilder();

    public abstract String getName();

    /**
     * 需要子类实现各自的转换
     */
    public Query convertToJoinIfNeed() {
        for (int i = 0; i < this.getNodeList().size(); i++) {
            if (this.getNodeList().get(i) instanceof Query) {
                this.getNodeList().set(i, ((Query) this.getNodeList().get(i)).convertToJoinIfNeed());
            }
        }

        return this;
    }

    public void assignment(Parameters parameters) {
        for (Node node : this.getNodeList()) {
            node.assignment(parameters);
        }

        this.indexQueryKeyFilter = OptimizerUtils.assignment(this.indexQueryKeyFilter, parameters);
        this.where = OptimizerUtils.assignment(this.where, parameters);
        this.allWhereFilter = OptimizerUtils.assignment(this.allWhereFilter, parameters);
        this.having = OptimizerUtils.assignment(this.having, parameters);
        this.resultFilter = OptimizerUtils.assignment(this.resultFilter, parameters);
        this.selectItemList = OptimizerUtils.assignment(this.selectItemList, parameters);
        this.otherJoinOnFilter = OptimizerUtils.assignment(this.otherJoinOnFilter, parameters);
        if (this.limitFrom instanceof BindValue) {
            Object value = ((BindValue) limitFrom).assignment(parameters);
            limitFrom = (Comparable) OptimizerUtils.convertType(value, Type.LongType);
        }

        if (this.limitTo instanceof BindValue) {
            Object value = ((BindValue) limitTo).assignment(parameters);
            limitTo = (Comparable) OptimizerUtils.convertType(value, Type.LongType);
        }
    }


    // =================== build / copy =========================

    public void setLimitFrom(Comparable limitFrom) {
        if (limitFrom != null && !(limitFrom instanceof BindValue)) {
            this.limitFrom = Long.valueOf(limitFrom.toString());
        }

        this.limitFrom = limitFrom;

    }


    public void setLimitTo(Comparable limitTo) {
        if (limitTo != null && !(limitTo instanceof BindValue)) {
            this.limitTo = Long.valueOf(limitTo.toString());
        }

        this.limitTo = limitTo;

    }

    public void limit(long from, long to) {
        this.setLimitFrom(from);
        this.setLimitTo(to);

    }


    public void setWhere(String where) {
        this.where = Filters.createFilter(where);

    }

    public void setWhereAndSetNeedBuild(Filter where) {
        this.where = where;
        setNeedBuild(true);

    }


    /**
     * 设置别名，表级别
     */
    public void setAlias(String alias) {
        this.setAliasAndSetNeedBuild(alias);

    }

    public void setAliasAndSetNeedBuild(String alias) {
        this.alias = alias;
        setNeedBuild(true);

    }

    public void setSubAliasAndSetNeedBuild(String subAlias) {
        this.subAlias = subAlias;
        setNeedBuild(true);

    }


    public void setGroupByListAndSetNeedBuild(List<OrderBy> groupByList) {
        this.groupByList = groupByList;
        setNeedBuild(true);

    }


    public void setOrderByListAndSetNeedBuild(List<OrderBy> orderByList) {
        this.orderByList = orderByList;
        setNeedBuild(true);
    }


    public void setResultFilterAndSetNeedBuild(Filter resultFilter) {
        this.resultFilter = resultFilter;
        setNeedBuild(true);
    }

    public void addResultFilter(BooleanFilter filter) {
        if (this.resultFilter == null) {
            this.resultFilter = filter;
            return;
        }

        this.resultFilter = DnfFilters.and(this.resultFilter, filter);
    }


    public void setIndexQueryKeyFilterAndSetNeedBuild(Filter indexQueryKeyFilter) {
        this.indexQueryKeyFilter = indexQueryKeyFilter;
        setNeedBuild(true);
    }

    /**
     * @return nodeList 方法名便于子节点命名
     */
    public List<Node> getNodeList() {
        return this.nodeList;
    }

    public Node getFirstSubNodeQueryNode() {
        if (this.getNodeList().isEmpty()) {
            return null;
        }
        return this.getNodeList().get(0);
    }

    public void addNode(Node node) {
        this.nodeList.add(node);
    }


    public void setSelectItemList(List<Item> selectItemList) {
        this.selectItemList = selectItemList;

    }

    public void setSelectItemList(Item... items) {
        this.setSelectItemListAndSetNeedBuild(new ArrayList<Item>(Arrays.asList(items)));

    }

    /**
     * 添加一个不存在的字段
     */
    public void addSelectItem(Item item) {
        if (!selectItemList.contains(item)) {
            selectItemList.add(item);
        }
    }

    /**
     * 添加一个不存在的字段
     */
    public void addReferedItem(Item item) {
        if (!referedItemList.contains(item)) {
            referedItemList.add(item);
        }
    }

    /**
     * 添加一个不存在的字段
     */
    public void addCorrelatedSubQueryItem(Item item) {
        boolean exist = false;
        for (Item correlatedSubQueryItem : correlatedSubQueryItemList) {
            if (correlatedSubQueryItem.getCorrelateSubQueryItemId().equals(item.getCorrelateSubQueryItemId())) {
                exist = true;
                break;
            }
        }

        if (!exist) {
            correlatedSubQueryItemList.add(item);
        }
    }

    /**
     * 判断一个字段是否存在
     */
    public boolean hasItem(Item item) {
        return this.getQueryNodeBuilder().getItem(item) != null;
    }

    /**
     * 根据字段获取一下字段，查询的字段可能来自于select或者from
     */
    public Item getItem(Item item) {
        return this.getQueryNodeBuilder().getItem(item);
    }

    public void setSelectItemListAndSetNeedBuild(List<Item> selectItemList) {
        this.selectItemList = selectItemList;
        setNeedBuild(true);

    }


    /**
     * 列的tableName会设为表别名
     */
    public List<Item> copySelectItemList() {
        List<Item> itemList = new ArrayList<Item>(this.getSelectItemList().size());
        for (Item item : this.getSelectItemList()) {
            Item itemCopy = item.copy();
            if (this.getAlias() != null) {
                itemCopy.setTableName(this.getAlias());
            }

            if (item.getAlias() != null) {
                itemCopy.setColumnName(item.getAlias()); // 设置为alias columnName
                itemCopy.setAlias(null);
            }
            itemList.add(itemCopy);
        }
        return itemList;
    }

    /**
     * 列的 tableName 会设为表别名
     */
    public List<Item> copyReferedItemList() {
        if (this.getAlias() == null) {
            return this.getReferedItemList();
        } else {
            List<Item> itemList = new ArrayList<Item>(this.getReferedItemList().size());
            for (Item item : this.getReferedItemList()) {
                Item itemCopy = item.copy();
                if (this.getAlias() != null) {
                    itemCopy.setTableName(this.getAlias());
                }

                if (item.getAlias() != null) {
                    itemCopy.setColumnName(item.getAlias()); // 设置为alias columnName
                    itemCopy.setAlias(null);
                }
                itemList.add(itemCopy);
            }
            return itemList;
        }
    }

    public Join join(Query query) {
        Join joinNode = new Join();
        joinNode.addNode(this);
        joinNode.addNode(query);
        return joinNode;
    }

    public Join join(String rightNode) {
        return this.join(new TableQuery(rightNode));
    }

    public Join join(String rightTable, String rightFilter, String leftKey, String rightKey) {
        //return this.join(new TableQuery(rightTable).setWhere(rightFilter)).addJoinKeys(leftKey, rightKey);
        TableQuery tableQueryNode = new TableQuery(rightTable);
        tableQueryNode.setWhere(rightFilter);
        //
        Join joinNode = this.join(tableQueryNode);
        joinNode.addJoinKeys(leftKey, rightKey);
        return joinNode;
    }

    public Join join(String rightTable, String rightFilter) {
        //return this.join(new TableQuery(rightTable).setWhere(rightFilter));
        TableQuery tableQueryNode = new TableQuery(rightTable);
        tableQueryNode.setWhere(rightFilter);
        Join joinNode = this.join(tableQueryNode);
        return joinNode;
    }

    public Join join(String rightTable, String leftKey, String rightKey) {
        // return this.join(new TableQuery(rightTable)).addJoinKeys(leftKey, rightKey);
        Join joinNode = this.join(new TableQuery(rightTable));
        joinNode.addJoinKeys(leftKey, rightKey);
        return joinNode;
    }

    public Join join(Query rightNode, String leftKey, String rightKey) {
        //return this.join(rightNode).addJoinKeys(leftKey, rightKey);
        Join joinNode = this.join(rightNode);
        joinNode.addJoinKeys(leftKey, rightKey);
        return joinNode;
    }

    public MergeQuery merge(Node node) {
        MergeQuery mergeQueryNode = new MergeQuery();
        mergeQueryNode.addNode(this);
        mergeQueryNode.addNode(node);
        return mergeQueryNode;
    }

    public MergeQuery merge(List<Node> nodeList) {
        MergeQuery mergeQueryNode = new MergeQuery();
        mergeQueryNode.addNode(this);
        mergeQueryNode.getNodeList().addAll(nodeList);
        return mergeQueryNode;
    }

    public void addGroupByItemAndSetNeedBuild(Item item, boolean asc) {
        OrderBy orderBy = ObjectCreateFactory.createOrderBy();
        orderBy.setColumn(item);
        orderBy.setAsc(asc);

        this.groupByList.add(orderBy);
        setNeedBuild(true);

    }

    public void addGroupByItemAndSetNeedBuild(Item item) {
        OrderBy orderBy = ObjectCreateFactory.createOrderBy();
        orderBy.setColumn(item);

        setNeedBuild(true);
        this.groupByList.add(orderBy);

    }

    public void addGroupByItemAndSetNeedBuild(String group) {
        this.addGroupByItemAndSetNeedBuild(OptimizerUtils.createColumnFromString(group));
    }

    public void addGroupByItemAndSetNeedBuild(OrderBy orderBy) {
        setNeedBuild(true);
        this.groupByList.add(orderBy);

    }

    public void addOrderByItemAndSetNeedBuild(Item item, boolean asc) {
        OrderBy orderBy = ObjectCreateFactory.createOrderBy();
        orderBy.setColumn(item);
        orderBy.setAsc(asc);

        if (!this.orderByList.contains(orderBy)) {
            this.orderByList.add(orderBy);
            setNeedBuild(true);
        }

    }

    public void addOrderByItemAndSetNeedBuild(String o) {
        addOrderByItemAndSetNeedBuild(o, true);
    }

    public void addOrderByItemAndSetNeedBuild(String o, boolean asc) {
        OrderBy orderBy = ObjectCreateFactory.createOrderBy();
        String column = o;
        orderBy.setAsc(asc);
        this.addOrderByItemAndSetNeedBuild(OptimizerUtils.createColumnFromString(column), orderBy.getAsc());
    }

    /**
     * 多个列时，允许逗号分隔
     */
    public void setSelectItemListAndSetNeedBuild(String string) {
        string = string.toLowerCase();
        List<Item> itemList = new ArrayList();
        for (String columnName : string.split(",")) {
            itemList.add(OptimizerUtils.createColumnFromString(columnName));
        }
        setSelectItemListAndSetNeedBuild(itemList);
    }


    /**
     * 设置别名，表级别
     */
    public void setTableSubAliasAndSetNeedBuild(String string) {
        this.setSubAliasAndSetNeedBuild(string);

    }


    public void setSubQueryAndSetNeedBuild(boolean subQuery) {
        setNeedBuild(true);
        this.subQuery = subQuery;

    }

    public boolean isNeedBuild() {
        if (this.needBuild) {
            return true;
        }

        // 如果子查询发生了改变，也需要重新build
        for (Node node : this.getNodeList()) {
            if (node.isNeedBuild()) {
                needBuild = true;
                return true;
            }
        }

        return false;
    }


    public void setConsistent(boolean consistent) {
        this.consistent = consistent;

    }


    public void having(Filter having) {
        this.having = having;

    }

    public void having(String having) {
        this.having = Filters.createFilter(having);

    }


    public boolean containsKeyFilter() {
        return this.indexQueryKeyFilter != null;
    }


    public void setOtherJoinOnFilter(Filter otherJoinOnFilter) {
        this.otherJoinOnFilter = otherJoinOnFilter;

    }


    public void setSubQueryId(Long subQueryId) {
        this.subQueryId = subQueryId;

    }

    public void setAllWhereFilter(Filter allWhereFilter) {
        this.allWhereFilter = allWhereFilter;

    }


    public void setSubQueryFunctionFilter(Filter subQueryFunctionFilter) {
        this.subQueryFunctionFilter = subQueryFunctionFilter;

    }


    public void setLockMode(LockMode lockMode) {
        this.lockMode = lockMode;

    }


    public void setExistAggregateExpression(boolean isExistAggregate) {
        this.existAggregateExpression = isExistAggregate;

    }


    public void setParent(Query parent) {
        this.parent = parent;

    }


    public void setCorrelatedSubQuery(boolean correlatedSubQuery) {
        this.correlatedSubQuery = correlatedSubQuery;

    }

    public Function getNextSubQueryFunction() {
        Function function = SubQueryPreProcessor.getNextSubQueryFunction(this);
        if (function != null) {
            return (Function) function.copy();
        } else {
            return null;
        }
    }

    /**
     * filter中的subquery生成执行计划
     */
    protected void subQueryToExecutePlan(int shareIndex) {
        List<Function> functionList = SubQueryPreProcessor.findSubQueryFunctionList(this, true);
        for (Function function : functionList) {
            Object query = function.getArgList().get(0);
            if (query instanceof Query) {
                ExecutePlan executePlan = ((Query) query).toExecutePlan(shareIndex);
                function.getArgList().set(0, executePlan);
            }
        }
    }

    /**
     * group by列和order by列重排序,对newOrderByList不必重新设置为orderByList
     * <pre>
     * 原理:
     * distinct和group by的字段顺序打乱的计算结果是等价的。
     * order by。列需要保证顺序不能打乱。但可以在原有的基础上追加新的排序列。
     * 1. 只存在group by，复制group by字段到order by
     * 2. group by列和order by列的相同长度部分,group by列满足order by列前缀列匹配，则可以进行调整。
     *    满足order by列前缀列匹配的情况有3种:group by列<=order by列（前缀部分重排序,上推）,group by列>order by列（前缀部分重排序,剩下部分append,整体上推）。
     *
     * 2.1group by列<=order by列（前缀部分重排序,上推）
     *      如 group by c1 c2 ,
     *        order by c2 c1，c3
     *        可优化为：
     *        group by c2 c1,
     *        order by c2 c1，c3
     * 2.2 group by列>order by列（前缀部分重排序,剩下部分append,整体上推）
     *      如:group by c1 c2 c3 ,
     *        order by c2 c1，
     *        可优化为：
     *        group by c2 c1 c3
     *        order by c2 c1 c3
     * </pre>
     */
    public List<OrderBy> getOrderByListCombinedWithGroupByList() {
        // order by列为空,group by不为空列，则复制group by列到order by列
        if (!$.isNotNullAndHasElement(this.getOrderByList())) {
            if ($.isNotNullAndHasElement(this.getGroupByList())) {
                return OptimizerUtils.copyOrderByList(this.getGroupByList());
            }
            return null;
        } else {
            if ($.isNotNullAndHasElement(this.getGroupByList())) {
                //order by列整体的每个元素对group by列整体的每个元素尝试order by列前缀匹配
                List<OrderBy> newOrderByList = new ArrayList<OrderBy>();
                for (OrderBy orderBy : this.getOrderByList()) {
                    if (findOrderByColumn(this.getGroupByList(), orderBy.getItem()) != null) {
                        newOrderByList.add(orderBy.copy());
                    } else {
                        //order by列在group by列里面不再进行匹配成功,则不再进行匹配。直接返回现有的order by列。
                        //group by :前缀列...
                        //order by :前缀列...
                        //
                        //只有当已经匹配的order by列与group by列数量刚好相等（group by列完全匹配），才允许已经前缀匹配的order by列上推。（上推条件）
                        if (newOrderByList.size() == this.getGroupByList().size()) {
                            this.setGroupByListAndSetNeedBuild(newOrderByList);
                        }
                        return this.getOrderByList();
                    }
                }
                //前缀匹配成功后追加group by剩下字段列
                for (OrderBy groupBy : this.getGroupByList()) {
                    if (findOrderByColumn(newOrderByList, groupBy.getItem()) == null) {
                        newOrderByList.add(groupBy.copy());
                    }
                }
                this.setGroupByListAndSetNeedBuild(newOrderByList);// 调整group by列。（一定满足上推条件）
                return newOrderByList;//order by列追加group by中排除前缀匹配后的列
            } else {
                return this.getOrderByList();
            }
        }

    }

    /**
     * 尝试查找一个同名的排序字段
     */
    protected OrderBy findOrderByColumn(List<OrderBy> orderByList, Item column) {
        for (OrderBy orderBy : orderByList) {
            if (orderBy.getItem().equals(column)) {
                return orderBy;
            }
        }

        return null;
    }

    /**
     * 复制数据到目标对象，注意此方法只会复制expression对象的引用
     */
    protected void copySelfTo(Query query) {
        query.setAlias(this.alias);
        query.setTableSubAliasAndSetNeedBuild(this.subAlias);
        query.selectItemList = this.getSelectItemList();
        query.referedItemList = this.getReferedItemList();
        query.groupByList = this.getGroupByList();
        query.orderByList = this.getOrderByList();
        query.where = (Filter) (this.where == null ? null : this.where.copy());
        query.having = (Filter) (this.having == null ? null : having.copy());
        query.indexQueryKeyFilter = (Filter) (this.indexQueryKeyFilter == null ? null : indexQueryKeyFilter.copy());
        query.resultFilter = (Filter) (this.resultFilter == null ? null : this.resultFilter.copy());
        query.allWhereFilter = (Filter) (this.allWhereFilter == null ? null : this.allWhereFilter.copy());
        query.otherJoinOnFilter = (Filter) (this.otherJoinOnFilter == null ? null : this.otherJoinOnFilter.copy());
        query.subQueryFunctionFilter = (Filter) (this.subQueryFunctionFilter == null ? null : this.subQueryFunctionFilter.copy());
        query.setLimitFrom(this.limitFrom);
        query.setLimitTo(this.limitTo);
        query.setNeedBuild(this.needBuild);
        query.setSql(this.getSql());
        query.setDataNodeId(this.getDataNodeId());
        query.setSubQueryAndSetNeedBuild(subQuery);
        query.setExistAggregateExpression(existAggregateExpression);
        query.setExistSequenceValue(existSequenceValue);
        query.setLockMode(this.lockMode);
        query.setCorrelatedSubQuery(this.correlatedSubQuery);
        query.setSubQueryId(this.subQueryId);
        query.setNeedBuild(false);
    }

    /**
     * 复制数据到目标对象，注意此方法会复制expression对象
     */
    protected void deepCopySelfTo(Query query) {
        query.setAlias(this.alias);
        query.setTableSubAliasAndSetNeedBuild(this.subAlias);
        query.selectItemList = OptimizerUtils.copySelectItemList(this.getSelectItemList());
        query.referedItemList = OptimizerUtils.copySelectItemList(this.getReferedItemList());
        query.correlatedSubQueryItemList = OptimizerUtils.copySelectItemList(this.correlatedSubQueryItemList);
        query.groupByList = OptimizerUtils.copyOrderByList(new ArrayList<OrderBy>(this.getGroupByList()));
        query.orderByList = OptimizerUtils.copyOrderByList(new ArrayList<OrderBy>(this.getOrderByList()));
        query.where = (Filter) (this.where == null ? null : this.where.copy());
        query.having = (Filter) (this.having == null ? null : having.copy());
        query.indexQueryKeyFilter = (Filter) (this.indexQueryKeyFilter == null ? null : indexQueryKeyFilter.copy());
        query.resultFilter = (Filter) (this.resultFilter == null ? null : this.resultFilter.copy());
        query.allWhereFilter = (Filter) (this.allWhereFilter == null ? null : this.allWhereFilter.copy());
        query.otherJoinOnFilter = (Filter) (otherJoinOnFilter == null ? null : otherJoinOnFilter.copy());
        query.subQueryFunctionFilter = (Filter) (this.subQueryFunctionFilter == null ? null : this.subQueryFunctionFilter.copy());

        if (this.getLimitFrom() instanceof BindValue) {
            query.setLimitFrom(((BindValue) this.getLimitFrom()).copy());
        } else {
            query.setLimitFrom(this.getLimitFrom());
        }

        if (this.getLimitTo() instanceof BindValue) {
            query.setLimitTo(((BindValue) this.getLimitTo()).copy());
        } else {
            query.setLimitTo(this.getLimitTo());
        }

        query.setSql(this.getSql());
        query.setDataNodeId(this.getDataNodeId());
        query.setSubQueryAndSetNeedBuild(this.isSubQuery());
        query.setNeedBuild(this.isNeedBuild());
        query.setExistAggregateExpression(existAggregateExpression);
        query.setExistSequenceValue(existSequenceValue);
        query.setLockMode(this.lockMode);
        query.setCorrelatedSubQuery(this.correlatedSubQuery);
        query.setSubQueryId(this.subQueryId);
        query.setNeedBuild(false);
    }

}
